package edu.bulsu.coe.serial;

import java.util.regex.*;
import java.util.*;

import jssc.SerialPort;
import jssc.SerialPortException;

public class Arduino{
	SerialPort port = null;
	
	public Arduino(String COMPort, int baud) throws SerialPortException{
		this(false, COMPort, baud);
	}
	
	public Arduino(boolean initTest, String COMPort, int baud) throws SerialPortException{
		System.out.println("[ARDUINO] Starting Arduino Class [initTest: " + initTest + ", port: " + COMPort + ", baud: " + baud + "]");
		port = new SerialPort(COMPort);
		port.openPort();
		port.setParams(baud, 8, 1, 0);
		if(initTest)
			testClass();
	}
	
	public int getRotation(){
		writeString("~");
		String resp = readString();
		Pattern p = Pattern.compile("-?\\d+");
		Matcher m = p.matcher(resp);
		m.find();
		return Integer.parseInt(m.group());
	}
	
	@Deprecated
	public int getLocationID(HashMap<String, Integer> locationList){
		List<String> locations = new ArrayList<String>(locationList.keySet());
		List<String> finalLocations = new ArrayList<String>();
		for(int i = 0; i < locations.size(); i++){
			int desPoint = locationList.get(locations.get(i));
			int srcPoint = getRotation();
			if(desPoint > srcPoint){
				finalLocations.add(locations.get(i));
			}
		}
		locations = finalLocations;
		int ret = 0, lastKey = -1;
		while(true){
			writeString("k");
			String resp = readString();
			if(resp.contains("k2") && ret > 0 && lastKey != 2){
				ret--;
				writeString("c3");
				writeString("p03" + locations.get(ret));
				lastKey = 2;
			}else if(resp.contains("k8") && ret < (locations.size() - 1) && lastKey != 8){
				ret++;
				writeString("c3");
				writeString("p03" + locations.get(ret));
				lastKey = 8;
			}else if(resp.contains("k11")){
				break;
			}else if(resp.contains("kn")){
				lastKey = -1;
			}
		}
		return locationList.get(locations.get(ret));
	}
	
	public int getKeypress(){
		int ret = 0, lastKey = -1;
		writeString("c3");
		boolean loopGet = true;
		while(loopGet){
			int currKey = -1;
			writeString("k");
			String resp = readString();
			writeString("p03" + ret);
			for(int i = 0; i <= 11; i++){
				if(resp.contains("k" + i)){
					currKey = i;
				}else if(resp.contains("k10")){
					writeString("c3");
					ret = 0;
					break;
				}else if(resp.contains("k11")){
					loopGet = false;
					//Avoid Immediate clicking of #
					try{Thread.sleep(1000);}catch(InterruptedException ie){}
					break;
				}
			}
			if(currKey != lastKey && currKey != -1){
				ret *= 10;
				ret += currKey;
			}
			lastKey = currKey;			
		}
		return ret;
	}
	
	private void testClass(){
		writeString("c");
		writeString("p00Connected to program");
		
		//Keypad test
		writeString("p01Keypad Test");
		System.out.println("[ARDUINO]" + getKeypress());
		
		//Rotation test
		writeString("p01Rotation Test");
		writeString("p02Press '#' to exit");
		for(;;){
			writeString("~");
			String resp = readString();
			writeString("p03" + resp);
			writeString("k");
			resp = readString();
			if(resp.contains("k11")) break;
		}
		
		//Single rotation 
		writeString("c");
		writeString("pProgram Synced!");
		writeString("p01End of test!");
		writeString("p02SRotation Test");
		writeString("p03Rotation count:" + getRotation());
		try{Thread.sleep(2500);}catch(Exception w){};
	}
	
	
	private void writeString(String string){
		//[ERR] Code 11 Arduino failed to get command or disconnected on loop
		try{
			Thread.sleep(5);
			port.writeString(string);
			Thread.sleep(25);
		}catch(Exception spe){
			System.out.println("[ARDUINO] Error 11: Device refused to accept value or disconnected");
			System.exit(0);
		}
	}
	
	private String readString(){
		//[ERR] Code 12 Arduino failed to send response or disconnected on loop
		try{
			Thread.sleep(5);
			String read = port.readString();
			Thread.sleep(25);
			return read;
		}catch(Exception spe){
			System.out.println("[ARDUINO] Error 12: Device refused to return a value or disconnected");
			System.exit(0);
			return null; //TODO I dunno why this is still needed?
		}
	}
	
	
	//Functions
	public void clear(){
		writeString("c");
	}
	
	public void clear(int row){
		if(row >= 0 && row <= 3){
			writeString("c" + row);
		}
	}
	
	public void writeScreen(String string){
		writeString("p" + string);
	}
	
	public void writeScreen(String string, int offset, int row){
		if(offset >= 0 && offset <= 19 && row >= 0 && row <= 3){
			writeString("p" + String.valueOf(offset) + String.valueOf(row) + string);
		}
	}
	public void cwriteScreen(String string, int offset, int row){
		clear(row);
		writeScreen(string, offset, row);
	}
}
